﻿using AppManager.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Threading.Tasks;
using System.Transactions;

namespace AppManager.DAL
{
    public class BaseDAL<T> where T : BaseModel
    {
        public static Db db = Db.Current;

        //public static TransactionScope GetTransaction()
        //{
        //    TransactionOptions option = new TransactionOptions()
        //    {
        //        IsolationLevel = IsolationLevel.ReadCommitted,
        //        Timeout = TimeSpan.FromSeconds(60),
        //    };

        //    //使用該屬性表示嵌套事務中不創建新的事務，也就是在所有嵌套的方法中所有的操作在一個事務中
        //    return new TransactionScope(TransactionScopeOption.Required, option);
        //}

        public static void Insert(T model)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                dbSet.Add(model);
                model.CreateDate = DateTime.Now;
                db.SaveChanges();
            }
        }
        public static void Delete(T model)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                T entityToDelete = dbSet.FirstOrDefault(s => s.Id == model.Id);
                if (entityToDelete != null)
                    dbSet.Remove(entityToDelete);
                db.SaveChanges();
            }
        }

        public static void Delete(Expression<Func<T, bool>> predicate)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                T entityToDelete = GetModel(predicate);
                if (entityToDelete != null)
                    dbSet.Remove(entityToDelete);
                db.SaveChanges();
            }
        }
        public static void Update(T entityToUpdate)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                entityToUpdate.UpdateDate = DateTime.Now;
                using (var newDb = new Db())
                {
                    newDb.Entry(entityToUpdate).State = EntityState.Modified;
                    newDb.SaveChanges();
                }
            }
        }

        public static void AddOrUpdate(T model)
        {
            if (model.Id > 0)
            {
                Update(model);
            }
            else
            {
                Insert(model);
            }
        }

        /// <summary>
        /// 局部更新
        /// </summary>
        /// <param name="propertyExpression"></param>
        /// <param name="entities"></param>
        /// <returns></returns>
        public static void UpdateIgnore(Expression<Func<T, object>> propertyExpression, params T[] entities)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                db.UpdateIgnore(propertyExpression, entities);
            }
        }


        /// <summary>
        /// 實現對像部分屬性的更新，newModel必須時匿名對象
        /// </summary>
        /// <param name="originalEntity"></param>
        /// <param name="newEntity">newModel必須時匿名對象（這樣是為了保證不加入多餘的屬性）</param>
        /// <returns></returns>
        public static void Update(T originalEntity, object newEntity)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                var entry = db.Entry(originalEntity);
                if (entry.State != EntityState.Unchanged)
                    entry.State = EntityState.Unchanged;
                entry.CurrentValues.SetValues(newEntity);
                db.SaveChanges();
            }
        }
        public static void InsertAll(IEnumerable<T> list)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                foreach (var item in list)
                {
                    item.CreateDate = DateTime.Now;
                }
                dbSet.AddRange(list);
                db.SaveChanges();
            }
        }
        public static void UpdateAll(IEnumerable<T> list)
        {
            using (var newDb = new Db())
            {
                foreach (var item in list)
                {
                    item.UpdateDate = DateTime.Now;
                    newDb.Entry(item).State = EntityState.Modified;
                }
                newDb.SaveChanges();
            }
        }
        public static void DeleteList(IEnumerable<T> list)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                dbSet.RemoveRange(list);
                db.SaveChanges();
            }
        }
        public static void DeleteList(Expression<Func<T, bool>> predicate = null)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                var list = GetList(predicate);
                dbSet.RemoveRange(list);
                db.SaveChanges();
            }
        }
        public static T GetModel(Expression<Func<T, bool>> predicate = null)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                return dbSet.FirstOrDefault(predicate);
            }
        }

        /// <summary>
        /// 如果查询为空，直接返回异常
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="notrack"></param>
        /// <returns></returns>
        public static IEnumerable<T> GetList(Expression<Func<T, bool>> predicate = null, bool notrack = false)
        {
            using (var db = new Db())
            {
                DbSet<T> dbSet = db.Set<T>();
                IEnumerable<T> list;
                if (predicate != null)
                {
                    if (notrack)
                    {
                        list = dbSet.Where(predicate).AsNoTracking().ToList().AsQueryable();
                    }
                    else
                    {
                        list = dbSet.Where(predicate).ToList();
                    }
                }
                else
                {
                    list = dbSet.ToList();
                }

                if (list == null)
                    throw new Exception("db null error");
                return list;
            }
        }
    }
}
